﻿using CoreWCF;
using SD.IdentitySystem;
using SD.Infrastructure.DTOBase;
using SD.Infrastructure.Membership;
using SlamDunk.MES.AppService.Maps;
using SlamDunk.MES.Domain.Entities.FoundationContext;
using SlamDunk.MES.Domain.Entities.ResourceContext;
using SlamDunk.MES.Domain.Entities.StockContext;
using SlamDunk.MES.Domain.IRepositories;
using SlamDunk.MES.Domain.Mediators;
using SlamDunk.MES.IAppService.DTOs.Inputs;
using SlamDunk.MES.IAppService.DTOs.Outputs.FoundationContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.StockContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SlamDunk.MES.AppService.Implements
{
    /// <summary>
    /// 库存单据服务契约实现
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults = true)]
    public class StockOrderContract : IStockOrderContract
    {
        #region # 字段及构造器

        /// <summary>
        /// 领域服务中介者
        /// </summary>
        private readonly DomainServiceMediator _svcMediator;

        /// <summary>
        /// 仓储中介者
        /// </summary>
        private readonly RepositoryMediator _repMediator;

        /// <summary>
        /// 单元事务
        /// </summary>
        private readonly IUnitOfWorkMES _unitOfWork;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public StockOrderContract(DomainServiceMediator svcMediator, RepositoryMediator repMediator, IUnitOfWorkMES unitOfWork)
        {
            this._svcMediator = svcMediator;
            this._repMediator = repMediator;
            this._unitOfWork = unitOfWork;
        }

        #endregion


        //命令部分

        #region # 创建库存单据类 —— void CreateStockOrderClass(string classNo, string className...
        /// <summary>
        /// 创建库存单据类
        /// </summary>
        /// <param name="classNo">库存单据类编号</param>
        /// <param name="className">库存单据类名称</param>
        /// <param name="directionType">出入库方向类型</param>
        /// <param name="generateBarcode">是否生成条码</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        public void CreateStockOrderClass(string classNo, string className, StockDirectionType directionType, bool? generateBarcode, Guid? facilityId, string description)
        {
            StockOrderClass stockOrderClass = new StockOrderClass(classNo, className, directionType, generateBarcode, facilityId, description);

            this._unitOfWork.RegisterAdd(stockOrderClass);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改库存单据类 —— void UpdateStockOrderClass(Guid stockOrderClassId, string classNo...
        /// <summary>
        /// 修改库存单据类
        /// </summary>
        /// <param name="stockOrderClassId">库存单据类Id</param>
        /// <param name="classNo">库存单据类编号</param>
        /// <param name="className">库存单据类名称</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        public void UpdateStockOrderClass(Guid stockOrderClassId, string classNo, string className, Guid? facilityId, string description)
        {
            StockOrderClass stockOrderClass = this._unitOfWork.Resolve<StockOrderClass>(stockOrderClassId);
            stockOrderClass.UpdateInfo(classNo, className, facilityId, description);

            this._unitOfWork.RegisterSave(stockOrderClass);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除库存单据类 —— void RemoveStockOrderClass(Guid stockOrderClassId)
        /// <summary>
        /// 删除库存单据类
        /// </summary>
        /// <param name="stockOrderClassId">库存单据类Id</param>
        public void RemoveStockOrderClass(Guid stockOrderClassId)
        {
            this._unitOfWork.RegisterRemove<StockOrderClass>(stockOrderClassId);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建入库单 —— void CreateStockInOrder(string orderNo, Guid stockOrderClassId...
        /// <summary>
        /// 创建入库单
        /// </summary>
        /// <param name="orderNo">单据编号</param>
        /// <param name="stockOrderClassId">库存单据类Id</param>
        /// <param name="sourceOrderType">源单据类型</param>
        /// <param name="sourceOrderId">源单据Id</param>
        /// <param name="sourceOrderName">源单据名称</param>
        /// <param name="targetStorageLocationType">目标储存位置类型</param>
        /// <param name="targetStorageLocationId">目标储存位置Id</param>
        /// <param name="targetStorageLocationName">目标储存位置名称</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        /// <param name="detailParams">入库单明细参数模型集</param>
        public void CreateStockInOrder(string orderNo, Guid stockOrderClassId, SourceOrderType? sourceOrderType, string sourceOrderId, string sourceOrderName, StorageLocationType targetStorageLocationType, string targetStorageLocationId, string targetStorageLocationName, Guid? facilityId, string description, IEnumerable<StockInOrderDetailParam> detailParams)
        {
            #region # 单据明细处理

            detailParams = detailParams?.ToArray() ?? Array.Empty<StockInOrderDetailParam>();

            #region # 验证

            if (!detailParams.Any())
            {
                throw new ArgumentNullException(nameof(detailParams), "入库单明细不可为空！");
            }

            #endregion

            IEnumerable<Guid> materialIds = detailParams.Where(x => x.materialLotParam != null).Select(x => x.materialId);
            IEnumerable<Guid> supplierIds = detailParams.Where(x => x.materialLotParam != null).Select(x => x.materialLotParam.supplierId);
            IDictionary<Guid, Material> materials = this._repMediator.MaterialRep.Find(materialIds);
            IDictionary<Guid, Enterprise> suppliers = this._repMediator.EnterpriseRep.Find(supplierIds);

            IList<StockOrderDetail> details = new List<StockOrderDetail>();
            foreach (StockInOrderDetailParam detailParam in detailParams)
            {
                Guid? materialLotId = null;

                #region # 物料批次处理

                if (detailParam.materialLotId.HasValue)
                {
                    materialLotId = detailParam.materialLotId.Value;
                }
                else if (detailParam.materialLotParam != null)
                {
                    MaterialLotParam materialLotParam = detailParam.materialLotParam;
                    MaterialLot materialLot = this._repMediator.MaterialLotRep.SingleOrDefault(detailParam.materialId, materialLotParam.supplierId, materialLotParam.productionBatchNo, materialLotParam.producedDate, materialLotParam.guaranteePeriod, materialLotParam.expiredDate, materialLotParam.receptionDate, materialLotParam.specification);
                    if (materialLot == null)
                    {
                        Material material = materials[detailParam.materialId];
                        Enterprise supplier = suppliers[materialLotParam.supplierId];
                        materialLot = new MaterialLot(material.Id, material.Number, material.Name, supplier.Id, supplier.Number, supplier.Name, materialLotParam.productionBatchNo, materialLotParam.producedDate, materialLotParam.guaranteePeriod, materialLotParam.expiredDate, materialLotParam.receptionDate, materialLotParam.specification, detailParam.quantity, materialLotParam.materialSourceType, material.FacilityId, null);

                        this._unitOfWork.RegisterAdd(materialLot);
                    }

                    materialLotId = materialLot.Id;
                }

                #endregion

                StockOrderDetail detail = new StockOrderDetail(detailParam.materialId, materialLotId, detailParam.quantity, detailParam.sort, detailParam.description, detailParam.relatedBarcodeNos);
                details.Add(detail);
            }

            #endregion

            StockOrderClass stockOrderClass = this._repMediator.StockOrderClassRep.Single(stockOrderClassId);

            #region # 验证

            if (stockOrderClass.DirectionType != StockDirectionType.Input)
            {
                throw new InvalidOperationException("库存单据类的出/入库方向类型必须为入库！");
            }

            #endregion

            StockInOrder stockInOrder = new StockInOrder(orderNo, stockOrderClass.Name, stockOrderClass.Id, sourceOrderType, sourceOrderId, sourceOrderName, targetStorageLocationType, targetStorageLocationId, targetStorageLocationName, stockOrderClass.GenerateBarcode!.Value, facilityId, description);
            stockInOrder.SetDetails(details);

            this._unitOfWork.RegisterAdd(stockInOrder);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改入库单 —— void UpdateStockInOrder(Guid stockInOrderId, StorageLocationType...
        /// <summary>
        /// 修改入库单
        /// </summary>
        /// <param name="stockInOrderId">入库单Id</param>
        /// <param name="targetStorageLocationType">目标储存位置类型</param>
        /// <param name="targetStorageLocationId">目标储存位置Id</param>
        /// <param name="targetStorageLocationName">目标储存位置名称</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        /// <param name="detailParams">入库单明细参数模型集</param>
        public void UpdateStockInOrder(Guid stockInOrderId, StorageLocationType targetStorageLocationType, string targetStorageLocationId, string targetStorageLocationName, Guid? facilityId, string description, IEnumerable<StockInOrderDetailParam> detailParams)
        {
            #region # 单据明细处理

            detailParams = detailParams?.ToArray() ?? Array.Empty<StockInOrderDetailParam>();

            #region # 验证

            if (!detailParams.Any())
            {
                throw new ArgumentNullException(nameof(detailParams), "入库单明细不可为空！");
            }

            #endregion

            IEnumerable<Guid> materialIds = detailParams.Where(x => x.materialLotParam != null).Select(x => x.materialId);
            IEnumerable<Guid> supplierIds = detailParams.Where(x => x.materialLotParam != null).Select(x => x.materialLotParam.supplierId);
            IDictionary<Guid, Material> materials = this._repMediator.MaterialRep.Find(materialIds);
            IDictionary<Guid, Enterprise> suppliers = this._repMediator.EnterpriseRep.Find(supplierIds);

            IList<StockOrderDetail> details = new List<StockOrderDetail>();
            foreach (StockInOrderDetailParam detailParam in detailParams)
            {
                Guid? materialLotId = null;

                #region # 物料批次处理

                if (detailParam.materialLotId.HasValue)
                {
                    materialLotId = detailParam.materialLotId.Value;
                }
                else if (detailParam.materialLotParam != null)
                {
                    MaterialLotParam materialLotParam = detailParam.materialLotParam;
                    MaterialLot materialLot = this._repMediator.MaterialLotRep.SingleOrDefault(detailParam.materialId, materialLotParam.supplierId, materialLotParam.productionBatchNo, materialLotParam.producedDate, materialLotParam.guaranteePeriod, materialLotParam.expiredDate, materialLotParam.receptionDate, materialLotParam.specification);
                    if (materialLot == null)
                    {
                        Material material = materials[detailParam.materialId];
                        Enterprise supplier = suppliers[materialLotParam.supplierId];
                        materialLot = new MaterialLot(material.Id, material.Number, material.Name, supplier.Id, supplier.Number, supplier.Name, materialLotParam.productionBatchNo, materialLotParam.producedDate, materialLotParam.guaranteePeriod, materialLotParam.expiredDate, materialLotParam.receptionDate, materialLotParam.specification, detailParam.quantity, materialLotParam.materialSourceType, material.FacilityId, null);

                        this._unitOfWork.RegisterAdd(materialLot);
                    }

                    materialLotId = materialLot.Id;
                }

                #endregion

                StockOrderDetail detail = new StockOrderDetail(detailParam.materialId, materialLotId, detailParam.quantity, detailParam.sort, detailParam.description, detailParam.relatedBarcodeNos);
                details.Add(detail);
            }

            #endregion

            StockInOrder stockInOrder = this._unitOfWork.Resolve<StockInOrder>(stockInOrderId);
            stockInOrder.UpdateInfo(targetStorageLocationType, targetStorageLocationId, targetStorageLocationName, facilityId, description);
            stockInOrder.SetDetails(details);

            this._unitOfWork.RegisterSave(stockInOrder);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建出库单 —— void CreateStockOutOrder(string orderNo, Guid stockOrderClassId...
        /// <summary>
        /// 创建出库单
        /// </summary>
        /// <param name="orderNo">单据编号</param>
        /// <param name="stockOrderClassId">库存单据类Id</param>
        /// <param name="sourceOrderType">源单据类型</param>
        /// <param name="sourceOrderId">源单据Id</param>
        /// <param name="sourceOrderName">源单据名称</param>
        /// <param name="sourceStorageLocationType">源储存位置类型</param>
        /// <param name="sourceStorageLocationId">源储存位置Id</param>
        /// <param name="sourceStorageLocationName">源储存位置名称</param>
        /// <param name="targetStorageLocationType">目标储存位置类型</param>
        /// <param name="targetStorageLocationId">目标储存位置Id</param>
        /// <param name="targetStorageLocationName">目标储存位置名称</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        /// <param name="detailParams">出库单明细参数模型集</param>
        public void CreateStockOutOrder(string orderNo, Guid stockOrderClassId, SourceOrderType? sourceOrderType, string sourceOrderId, string sourceOrderName, StorageLocationType sourceStorageLocationType, string sourceStorageLocationId, string sourceStorageLocationName, StorageLocationType targetStorageLocationType, string targetStorageLocationId, string targetStorageLocationName, Guid? facilityId, string description, IEnumerable<StockOutOrderDetailParam> detailParams)
        {
            detailParams = detailParams?.ToArray() ?? Array.Empty<StockOutOrderDetailParam>();

            #region # 验证

            if (!detailParams.Any())
            {
                throw new ArgumentNullException(nameof(detailParams), "出库单明细不可为空！");
            }

            #endregion

            IEnumerable<StockOrderDetail> details =
                from detailParam in detailParams
                select new StockOrderDetail(detailParam.materialId, detailParam.materialLotId, detailParam.quantity, detailParam.sort, detailParam.description, detailParam.relatedBarcodeNos);

            StockOrderClass stockOrderClass = this._repMediator.StockOrderClassRep.Single(stockOrderClassId);

            #region # 验证

            if (stockOrderClass.DirectionType != StockDirectionType.Output)
            {
                throw new InvalidOperationException("库存单据类的出/入库方向类型必须为出库！");
            }

            #endregion

            StockOutOrder stockOutOrder = new StockOutOrder(orderNo, stockOrderClass.Name, stockOrderClass.Id, sourceOrderType, sourceOrderId, sourceOrderName, sourceStorageLocationType, sourceStorageLocationId, sourceStorageLocationName, targetStorageLocationType, targetStorageLocationId, targetStorageLocationName, facilityId, description);
            stockOutOrder.SetDetails(details);

            this._unitOfWork.RegisterAdd(stockOutOrder);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改出库单 —— void UpdateStockOutOrder(Guid stockOutOrderId, StorageLocationType...
        /// <summary>
        /// 修改出库单
        /// </summary>
        /// <param name="stockOutOrderId">出库单Id</param>
        /// <param name="sourceStorageLocationType">源储存位置类型</param>
        /// <param name="sourceStorageLocationId">源储存位置Id</param>
        /// <param name="sourceStorageLocationName">源储存位置名称</param>
        /// <param name="targetStorageLocationType">目标储存位置类型</param>
        /// <param name="targetStorageLocationId">目标储存位置Id</param>
        /// <param name="targetStorageLocationName">目标储存位置名称</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        /// <param name="detailParams"></param>
        public void UpdateStockOutOrder(Guid stockOutOrderId, StorageLocationType sourceStorageLocationType, string sourceStorageLocationId, string sourceStorageLocationName, StorageLocationType targetStorageLocationType, string targetStorageLocationId, string targetStorageLocationName, Guid? facilityId, string description, IEnumerable<StockOutOrderDetailParam> detailParams)
        {
            detailParams = detailParams?.ToArray() ?? Array.Empty<StockOutOrderDetailParam>();

            #region # 验证

            if (!detailParams.Any())
            {
                throw new ArgumentNullException(nameof(detailParams), "出库单明细不可为空！");
            }

            #endregion

            IEnumerable<StockOrderDetail> details =
                from detailParam in detailParams
                select new StockOrderDetail(detailParam.materialId, detailParam.materialLotId, detailParam.quantity, detailParam.sort, detailParam.description, detailParam.relatedBarcodeNos);

            StockOutOrder stockOutOrder = this._unitOfWork.Resolve<StockOutOrder>(stockOutOrderId);
            stockOutOrder.UpdateInfo(sourceStorageLocationType, sourceStorageLocationId, sourceStorageLocationName, targetStorageLocationType, targetStorageLocationId, targetStorageLocationName, facilityId, description);
            stockOutOrder.SetDetails(details);

            this._unitOfWork.RegisterSave(stockOutOrder);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除库存单据 —— void RemoveStockOrder(Guid stockOrderId)
        /// <summary>
        /// 删除库存单据
        /// </summary>
        /// <param name="stockOrderId">库存单据Id</param>
        public void RemoveStockOrder(Guid stockOrderId)
        {
            StockOrder stockOrder = this._unitOfWork.Resolve<StockOrder>(stockOrderId);

            #region # 验证

            if (stockOrder.CheckStatus == CheckStatus.Checking)
            {
                throw new InvalidOperationException("审核中的库存单据不可删除！");
            }
            if (stockOrder.CheckStatus == CheckStatus.Passed)
            {
                throw new InvalidOperationException("审核通过的库存单据不可删除！");
            }

            #endregion

            this._unitOfWork.RegisterRemove(stockOrder);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 提交审核库存单据 —— void SubmitStockOrder(Guid stockOrderId)
        /// <summary>
        /// 提交审核库存单据
        /// </summary>
        /// <param name="stockOrderId">库存单据Id</param>
        public void SubmitStockOrder(Guid stockOrderId)
        {
            //获取当前用户
            LoginInfo loginInfo = MembershipMediator.GetLoginInfo();
            string operatorAccount = loginInfo?.LoginId;
            string operatorName = loginInfo?.RealName;

            StockOrder stockOrder = this._unitOfWork.Resolve<StockOrder>(stockOrderId);
            stockOrder.Submit(operatorAccount, operatorName);

            this._unitOfWork.RegisterSave(stockOrder);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 批量提交审核库存单据 —— void SubmitStockOrders(IEnumerable<Guid>...
        /// <summary>
        /// 批量提交审核库存单据
        /// </summary>
        /// <param name="stockOrderIds">库存单据Id集</param>
        public void SubmitStockOrders(IEnumerable<Guid> stockOrderIds)
        {
            #region # 验证

            stockOrderIds = stockOrderIds?.Distinct().ToArray() ?? Array.Empty<Guid>();
            if (!stockOrderIds.Any())
            {
                return;
            }

            #endregion

            //获取当前用户
            LoginInfo loginInfo = MembershipMediator.GetLoginInfo();
            string operatorAccount = loginInfo?.LoginId;
            string operatorName = loginInfo?.RealName;

            ICollection<StockOrder> stockOrders = this._unitOfWork.ResolveRange<StockOrder>(stockOrderIds);
            foreach (StockOrder stockOrder in stockOrders)
            {
                stockOrder.Submit(operatorAccount, operatorName);
            }

            this._unitOfWork.RegisterSaveRange(stockOrders);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 审核库存单据 —— void CheckStockOrder(Guid stockOrderId...
        /// <summary>
        /// 审核库存单据
        /// </summary>
        /// <param name="stockOrderId">库存单据Id</param>
        /// <param name="passed">是否通过</param>
        /// <param name="checkedRemark">审核意见</param>
        public void CheckStockOrder(Guid stockOrderId, bool passed, string checkedRemark)
        {
            //获取当前用户
            LoginInfo loginInfo = MembershipMediator.GetLoginInfo();
            string operatorAccount = loginInfo?.LoginId;
            string operatorName = loginInfo?.RealName;

            StockOrder stockOrder = this._unitOfWork.Resolve<StockOrder>(stockOrderId);
            stockOrder.Check(passed, checkedRemark, operatorAccount, operatorName);

            //审核通过
            if (passed)
            {
                ICollection<StockSettlement> stockSettlements = this._svcMediator.StockOrderSvc.GenerateStockSettlements(stockOrder);
                ICollection<MaterialBarcode> materialBarcodes = this._svcMediator.StockOrderSvc.GenerateMaterialBarcodes(stockOrder);
                ICollection<BoundRecord> boundRecords = this._svcMediator.StockOrderSvc.GenerateBoundRecords(stockOrder);
                if (stockSettlements.Any())
                {
                    this._unitOfWork.RegisterAddRange(stockSettlements);
                }
                if (materialBarcodes.Any())
                {
                    this._unitOfWork.RegisterAddRange(materialBarcodes);
                }
                if (boundRecords.Any())
                {
                    this._unitOfWork.RegisterAddRange(boundRecords);
                }
            }

            this._unitOfWork.RegisterSave(stockOrder);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 打印库存单据条码 —— void PrintStockOrderBarcode(Guid stockOrderId, Guid stockOrderDetailId)
        /// <summary>
        /// 打印库存单据条码
        /// </summary>
        /// <param name="stockOrderId">库存单据Id</param>
        /// <param name="stockOrderDetailId">库存单据明细Id</param>
        public void PrintStockOrderBarcode(Guid stockOrderId, Guid stockOrderDetailId)
        {
            StockOrder stockOrder = this._unitOfWork.Resolve<StockOrder>(stockOrderId);
            StockOrderDetail stockOrderDetail = stockOrder.GetDetail(stockOrderDetailId);
            stockOrderDetail.PrintBarcodes();

            this._unitOfWork.RegisterSave(stockOrder);
            this._unitOfWork.Commit();
        }
        #endregion


        //查询部分

        #region # 分页获取库存单据类列表 —— PageModel<StockOrderClassInfo> GetStockOrderClassesByPage(...
        /// <summary>
        /// 分页获取库存单据类列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="directionType">出/入库方向类型</param>
        /// <param name="generateBarcode">是否生成条码</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>库存单据类列表</returns>
        public PageModel<StockOrderClassInfo> GetStockOrderClassesByPage(string keywords, StockDirectionType? directionType, bool? generateBarcode, Guid? facilityId, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<StockOrderClass> stockOrderClasses = this._repMediator.StockOrderClassRep.FindByPage(keywords, directionType, generateBarcode, relatedFacilityIds, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> facilityIds = stockOrderClasses.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<StockOrderClassInfo> stockOrderClassInfos = stockOrderClasses.Select(x => x.ToDTO(facilityInfos));

            return new PageModel<StockOrderClassInfo>(stockOrderClassInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取入库单列表 —— PageModel<StockInOrderInfo> GetStockInOrdersByPage(string keywords...
        /// <summary>
        /// 分页获取入库单列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="stockOrderClassId">库存单据类Id</param>
        /// <param name="checkStatus">审核状态</param>
        /// <param name="sourceOrderType">源单据类型</param>
        /// <param name="sourceOrderId">源单据Id</param>
        /// <param name="targetStorageLocationType">目标储存位置类型</param>
        /// <param name="targetStorageLocationId">目标储存位置Id</param>
        /// <param name="generateBarcode">是否生成条码</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>入库单列表</returns>
        public PageModel<StockInOrderInfo> GetStockInOrdersByPage(string keywords, Guid? stockOrderClassId, CheckStatus? checkStatus, SourceOrderType? sourceOrderType, string sourceOrderId, StorageLocationType? targetStorageLocationType, string targetStorageLocationId, bool? generateBarcode, DateTime? startTime, DateTime? endTime, Guid? facilityId, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<StockInOrder> stockInOrders = this._repMediator.StockOrderRep.FindStockInOrdersByPage(keywords, stockOrderClassId, checkStatus, sourceOrderType, sourceOrderId, targetStorageLocationType, targetStorageLocationId, generateBarcode, startTime, endTime, relatedFacilityIds, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> facilityIds = stockInOrders.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<StockInOrderInfo> stockInOrderInfos = stockInOrders.Select(x => x.ToDTO(facilityInfos));

            return new PageModel<StockInOrderInfo>(stockInOrderInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取出库单列表 —— PageModel<StockOutOrderInfo> GetStockOutOrdersByPage(string keywords...
        /// <summary>
        /// 分页获取出库单列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="stockOrderClassId">库存单据类Id</param>
        /// <param name="checkStatus">审核状态</param>
        /// <param name="sourceOrderType">源单据类型</param>
        /// <param name="sourceOrderId">源单据Id</param>
        /// <param name="sourceStorageLocationType">源储存位置类型</param>
        /// <param name="sourceStorageLocationId">目标储存位置Id</param>
        /// <param name="targetStorageLocationType">目标储存位置类型</param>
        /// <param name="targetStorageLocationId">目标储存位置Id</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>出库单列表</returns>
        public PageModel<StockOutOrderInfo> GetStockOutOrdersByPage(string keywords, Guid? stockOrderClassId, CheckStatus? checkStatus, SourceOrderType? sourceOrderType, string sourceOrderId, StorageLocationType? sourceStorageLocationType, string sourceStorageLocationId, StorageLocationType? targetStorageLocationType, string targetStorageLocationId, DateTime? startTime, DateTime? endTime, Guid? facilityId, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<StockOutOrder> stockInOrders = this._repMediator.StockOrderRep.FindStockOutOrdersByPage(keywords, stockOrderClassId, checkStatus, sourceOrderType, sourceOrderId, sourceStorageLocationType, sourceStorageLocationId, targetStorageLocationType, targetStorageLocationId, startTime, endTime, relatedFacilityIds, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> facilityIds = stockInOrders.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<StockOutOrderInfo> stockInOrderInfos = stockInOrders.Select(x => x.ToDTO(facilityInfos));

            return new PageModel<StockOutOrderInfo>(stockInOrderInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 获取库存单据明细列表 —— IEnumerable<StockOrderDetailInfo> GetStockOrderDetails(Guid stockOrderId)
        /// <summary>
        /// 获取库存单据明细列表
        /// </summary>
        /// <param name="stockOrderId">库存单据Id</param>
        /// <returns>库存单据明细列表</returns>
        public IEnumerable<StockOrderDetailInfo> GetStockOrderDetails(Guid stockOrderId)
        {
            ICollection<StockOrderDetail> details = this._repMediator.StockOrderDetailRep.Find(stockOrderId);

            IEnumerable<Guid> materialIds = details.Select(x => x.MaterialId);
            IEnumerable<Guid> materialLotIds = details.Where(x => x.MaterialLotId.HasValue).Select(x => x.MaterialLotId.Value);
            IDictionary<Guid, MaterialInfo> materialInfos = this._repMediator.MaterialRep.Find(materialIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, MaterialLotInfo> materialLotInfos = this._repMediator.MaterialLotRep.Find(materialLotIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));

            IEnumerable<StockOrderDetailInfo> detailInfos = details.Select(x => x.ToDTO(materialInfos, materialLotInfos));

            return detailInfos;
        }
        #endregion
    }
}
